#include <cubefs/api/api.hpp>
#include <natives.h>
#include <decls.hpp>
#include <exceptions.hpp>

#include <cubefs/core/tools/types/dispatcher.hpp>

#define CUBEFS_SOURCE "value.cpp:" CUBEFS_AT

using namespace cubefs::api;
using namespace cubefs::tools;

using namespace std;

JNIEXPORT jlong JNICALL METADATA1(TypedNumber, newValue) (JNIEnv *env, jclass, jint code) {
    CUBEFS_EXC_BEGIN
    Typed* value = NULL;

    switch (code) {
        case 0 : value = new TypedNumber<Int>();    break;
        case 1 : value = new TypedNumber<BigInt>(); break;
        case 2 : value = new TypedNumber<bool>();   break;
        case 3 : value = new TypedNumber<float>();  break;
        case 4 : value = new TypedNumber<double>(); break;
        case 5 : value = new TypedNumber<Short>();  break;
        case 6 : value = new TypedNumber<UShort>(); break;
        case 7 : value = new TypedNumber<Byte>();   break;
        default: throw CubefsException(CUBEFS_SOURCE, "Unrecognized TypedValue code");
    }

    return Ptr2Handle(value);
    CUBEFS_EXC_HANDLE
    return 0;
}

Number* convertToNumber(Typed* value) {
    if (!value->IsInstance(Number::MyType())) {
        throw TypeCastException(CUBEFS_SOURCE, "Specified value is not a Number: " + value->type()->name(), value->type(), Number::MyType());
    }
    else {
        return static_cast<Number*>(value);
    }
}

JNIEXPORT jint JNICALL METADATA1(Number, getIntValue) (JNIEnv *env, jclass, jlong handle) {
    CUBEFS_EXC_BEGIN

    Typed* value = Handle2Ptr<Typed>(handle);
    return convertToNumber(value)->getIntValue();

    CUBEFS_EXC_HANDLE
    return 0;
}

JNIEXPORT jlong JNICALL METADATA1(Number, getLongValue) (JNIEnv *env, jclass, jlong handle) {
    CUBEFS_EXC_BEGIN

    Typed* value = Handle2Ptr<Typed>(handle);
    return convertToNumber(value)->getLongValue();

    CUBEFS_EXC_HANDLE
    return 0;
}


JNIEXPORT jboolean JNICALL METADATA1(Number, getBooleanValue) (JNIEnv *env, jclass, jlong handle) {
    CUBEFS_EXC_BEGIN

    Typed* value = Handle2Ptr<Typed>(handle);
    return convertToNumber(value)->getBoolValue();

    CUBEFS_EXC_HANDLE
    return 0;
}


JNIEXPORT jfloat JNICALL METADATA1(Number, getFloatValue) (JNIEnv *env, jclass, jlong handle) {
    CUBEFS_EXC_BEGIN

    Typed* value = Handle2Ptr<Typed>(handle);
    return convertToNumber(value)->getFloatValue();

    CUBEFS_EXC_HANDLE
    return 0;
}

JNIEXPORT jdouble JNICALL METADATA1(Number, getDoubleValue) (JNIEnv *env, jclass, jlong handle) {
    CUBEFS_EXC_BEGIN

    Typed* value = Handle2Ptr<Typed>(handle);
    return convertToNumber(value)->getDoubleValue();

    CUBEFS_EXC_HANDLE
    return 0;
}

JNIEXPORT jshort JNICALL METADATA1(Number, getShortValue) (JNIEnv *env, jclass, jlong handle) {
    CUBEFS_EXC_BEGIN

    Typed* value = Handle2Ptr<Typed>(handle);
    return convertToNumber(value)->getShortValue();

    CUBEFS_EXC_HANDLE
    return 0;
}

JNIEXPORT jchar JNICALL METADATA1(Number, getCharacterValue) (JNIEnv *env, jclass, jlong handle) {
    CUBEFS_EXC_BEGIN

    Typed* value = Handle2Ptr<Typed>(handle);
    return convertToNumber(value)->getUShortValue();

    CUBEFS_EXC_HANDLE
    return 0;
}

JNIEXPORT jbyte JNICALL METADATA1(Number, getByteValue) (JNIEnv *env, jclass, jlong handle) {
    CUBEFS_EXC_BEGIN

    Typed* value = Handle2Ptr<Typed>(handle);
    return convertToNumber(value)->getByteValue();

    CUBEFS_EXC_HANDLE
    return 0;
}



JNIEXPORT void JNICALL METADATA1(Number, setIntValue) (JNIEnv *env, jclass, jlong handle, jint v) {
    CUBEFS_EXC_BEGIN

    Typed* value = Handle2Ptr<Typed>(handle);
    return convertToNumber(value)->setIntValue(v);

    CUBEFS_EXC_HANDLE
}

JNIEXPORT void JNICALL METADATA1(Number, setLongValue) (JNIEnv *env, jclass, jlong handle, jlong v) {
    CUBEFS_EXC_BEGIN

    Typed* value = Handle2Ptr<Typed>(handle);
    return convertToNumber(value)->setLongValue(v);

    CUBEFS_EXC_HANDLE
}

JNIEXPORT void JNICALL METADATA1(Number, setFloatValue) (JNIEnv *env, jclass, jlong handle, jfloat v) {
    CUBEFS_EXC_BEGIN

    Typed* value = Handle2Ptr<Typed>(handle);
    return convertToNumber(value)->setFloatValue(v);

    CUBEFS_EXC_HANDLE
}

JNIEXPORT void JNICALL METADATA1(Number, setDoubleValue) (JNIEnv *env, jclass, jlong handle, jdouble v) {
    CUBEFS_EXC_BEGIN

    Typed* value = Handle2Ptr<Typed>(handle);
    return convertToNumber(value)->setDoubleValue(v);

    CUBEFS_EXC_HANDLE
}

JNIEXPORT void JNICALL METADATA1(Number, setShortValue) (JNIEnv *env, jclass, jlong handle, jshort v) {
    CUBEFS_EXC_BEGIN

    Typed* value = Handle2Ptr<Typed>(handle);
    return convertToNumber(value)->setShortValue(v);

    CUBEFS_EXC_HANDLE
}

JNIEXPORT void JNICALL METADATA1(Number, setByteValue) (JNIEnv *env, jclass, jlong handle, jbyte v) {
    CUBEFS_EXC_BEGIN

    Typed* value = Handle2Ptr<Typed>(handle);
    return convertToNumber(value)->setByteValue(v);

    CUBEFS_EXC_HANDLE
}


JNIEXPORT void JNICALL METADATA1(Number, setCharacterValue) (JNIEnv *env, jclass, jlong handle, jchar v) {
    CUBEFS_EXC_BEGIN

    Typed* value = Handle2Ptr<Typed>(handle);
    return convertToNumber(value)->setUShortValue(v);

    CUBEFS_EXC_HANDLE
}

JNIEXPORT void JNICALL METADATA1(Number, setBooleanValue) (JNIEnv *env, jclass, jlong handle, jboolean v) {
    CUBEFS_EXC_BEGIN

    Typed* value = Handle2Ptr<Typed>(handle);
    return convertToNumber(value)->setBoolValue(v);

    CUBEFS_EXC_HANDLE
}

JNIEXPORT jstring JNICALL METADATA1(IDValue, text) (JNIEnv *env, jclass, jlong handle) {
    CUBEFS_EXC_BEGIN

    TypedIDValue* value = Handle2Ptr<TypedIDValue>(handle);
    return env->NewStringUTF(value->getValue().str().c_str());

    CUBEFS_EXC_HANDLE
    return NULL;
}

JNIEXPORT jboolean JNICALL METADATA1(IDValue, isNull) (JNIEnv *env, jclass, jlong handle) {
    CUBEFS_EXC_BEGIN

    TypedIDValue* value = Handle2Ptr<TypedIDValue>(handle);
    return value->getValue().IsNull();

    CUBEFS_EXC_HANDLE
    return NULL;
}


JNIEXPORT jboolean JNICALL METADATA1(IDValue, equals) (JNIEnv *env, jclass, jlong me, jlong otherh) {
    CUBEFS_EXC_BEGIN

    TypedIDValue* value = Handle2Ptr<TypedIDValue>(me);
    TypedIDValue* other = Handle2Ptr<TypedIDValue>(otherh);
    return value->getValue().equals(other->getValue());

    CUBEFS_EXC_HANDLE
    return NULL;
}

#undef CUBEFS_SOURCE
